<?php

// Namespace

namespace Loop;


/**
 * CVariableManager is a class that handles variables used by the models, views and controllers
 */

class CVariableManager
{
	// Properties
	
	private $variables = null;
	
	
	/**
	 * Constructs a variable manager
	 */
	
	public function __construct()
	{
		$this->variables = array();
	}
	
	
	/**
	 * Deletes a group of variables
	 *
	 * @param 	string 	$variableGroup 	The name of the variable group
	 */
	
	public function deleteVariableGroup($variableGroup)
	{
		if (isset($this->variables[$variableGroup]) == true)
		{
			unset($this->variables[$variableGroup]);
		}
	}
	
	
	/**
	 * Extracts the group ad name of a variable from its path
	 *
	 * @param 	string 	$variablePath	The path to the variable
	 * @param 	string	$variableGroup 	A reference to the variable group
	 * @param 	string	$variableName	A reference to the variable name
	 */
	
	private function extractGroupAndNameFromPath($variablePath, &$variableGroup, &$variableName)
	{
		// Get the group and name of the variable
		
		$pattern = '/^(([a-zA-Z_]*)::)?(.+)$/';
		
		if (preg_match($pattern, $variablePath, $matches) == false)
		{
			e
			(
				EXCEPTION_VARIABLE_PATH_NOT_VALID,
				array
				(
					'pattern' => $pattern,
					'variablePath' => $variablePath
				)
			);
		}
		
		$variableGroup = $matches[2];
		$variableName = $matches[3];
		
		
		// Syntaxes v('foo') and v('::foo') (current view or page)
		
		if (empty($variableGroup) == true)
		{
			if ($matches[1] == '::')
			{
				$variableGroup = ns(true, false);
			}
			else
			{
				$variableGroup = ns(false, false);
			}
		}
	}
	
	
	/**
	 * Looks for a variable in all places (locally > globally > GET > POST)
	 *
	 * @param 	string 	$variableName		The name of the variable
	 * @param 	bool 	$isValueRequired 	True to ensure the variable has got a value, false otherwise
	 * @param 	mixed 	$defaultValue		In case variable is not required, use the default value
	 *
	 * @return	mixed 	The value of the variable
	 */
	
	public function findVariable($variableName, $isValueRequired = false, $defaultValue = null)
	{
		// At first, we've got no value
		
		$variableValue = null;
		
		
		// Get the internal+external values
		
		$valueFromLocal = v($variableName);
		$valueFromGlobal = v('::' . $variableName);
		$valueFromGet = v('GET::' . $variableName);
		$valueFromPost = v('POST::' . $variableName);
		$valueFromSession = v('SESSION::' . $variableName);
		$valueFromCookie = v('COOKIE::' . $variableName);
		$valueFromArgs = v('ARGS::' . $variableName);
		
		if ($valueFromLocal !== null)
		{
			$variableValue = $valueFromLocal;
		}
		else if ($valueFromGlobal !== null)
		{
			$variableValue = $valueFromGlobal;
		}
		else if ($valueFromGet !== null)
		{
			$variableValue = $valueFromGet;
		}
		else if ($valueFromPost !== null)
		{
			$variableValue = $valueFromPost;
		}
		else if ($valueFromSession !== null)
		{
			$variableValue = $valueFromSession;
		}
		else if ($valueFromCookie !== null)
		{
			$variableValue = $valueFromCookie;
		}
		else if ($valueFromArgs !== null)
		{
			$variableValue = $valueFromArgs;
		}
		
		
		// If required, is the argument empty?
		
		if (is_null($variableValue) == true)
		{
			if ($isValueRequired == true)
			{
				e
				(
					EXCEPTION_VARIABLE_NOT_FOUND,
					array
					(
						'variableName' => $variableName
					)
				);
			}
			else
			{
				$variableValue = $defaultValue;
			}
		}


		return $variableValue;
	}
	
	
	/**
	 * Gets the value (clean and safe) of a variable
	 *
	 * @param 	string 	$variablePath 	The path to the variable
	 *
	 * @return 	mixed 	The variable (or null if none found)
	 */
	
	public function getVariable($variablePath)
	{
		// Extract the variable group/name
		
		$this->extractGroupAndNameFromPath($variablePath, $variableGroup, $variableName);
		
		
		// Make sure the variable exists
		
		if ($variableGroup == 'ARGS')
		{
			if ($variableName == '*')
			{
				return array();
			}
			else
			{
				// Get the variable from the command line
								
				$options = getopt(null, array($variableName . '::'));

				if (isset($options[$variableName]) == true)
				{
					return $this->sanitizeVariable($options[$variableName]);
				}			
			}
		}
		else if ($variableGroup == 'COOKIE')
		{
			if ($variableName == '*')
			{
				return $_COOKIE;
			}
			else
			{
				if (isset($_COOKIE[pref('[Loop]/cookie/prefix') . $variableName]) == true)
				{
					return $this->sanitizeVariable($_COOKIE[pref('[Loop]/cookie/prefix') . $variableName]);
				}
			}
		}
		else if ($variableGroup == 'FILE')
		{
			if ($variableName == '*')
			{
				return $_FILE;
			}
			else
			{
				if (isset($_FILE[$variableName]) == true)
				{
					if (is_null($_FILE[$variableName]) == true)
					{
						return true;
					}
					else
					{
						return $this->sanitizeVariable($_FILE[$variableName]);
					}
				}
			}
		}
		else if ($variableGroup == 'GET')
		{
			if ($variableName == '*')
			{
				return $_GET;
			}
			else
			{
				if (isset($_GET[$variableName]) == true)
				{
					if (is_null($_GET[$variableName]) == true)
					{
						return true;
					}
					else
					{
						return $this->sanitizeVariable($_GET[$variableName]);
					}
				}
			}
		}
		else if ($variableGroup == 'POST')
		{
			if ($variableName == '*')
			{
				return $_POST;
			}
			else
			{
				if (isset($_POST[$variableName]) == true)
				{
					if (is_null($_POST[$variableName]) == true)
					{
						return true;
					}
					else
					{
						return $this->sanitizeVariable($_POST[$variableName]);
					}
				}
			}
		}
		else if ($variableGroup == 'SERVER')
		{
			if ($variableName == '*')
			{
				return $_SERVER;
			}
			else
			{
				if (isset($_SERVER[$variableName]) == true)
				{
					return $this->sanitizeVariable($_SERVER[$variableName]);
				}
			}
		}
		else if ($variableGroup == 'SESSION')
		{
			if ($variableName == '*')
			{
				return $_SESSION;
			}
			else
			{
				if (isset($_SESSION[$variableName]) == true)
				{
					return $this->sanitizeVariable($_SESSION[$variableName]);
				}
			}
		}
		else if (isset($this->variables[$variableGroup]) == true)
		{
			if ($variableName == '*')
			{
				return $this->variables[$variableGroup];
			}
			else
			{
				if (isset($this->variables[$variableGroup][$variableName]) == true)
				{
					return $this->variables[$variableGroup][$variableName];
				}
			}
		}
	}
	
	
	/**
	 * Makes sure a variable is clean and returns it
	 *
	 * @param 	string 	$variableValue 	The variable to be checked
	 *
	 * @return 	string 	The new value of the variable
	 */
	
	private function sanitizeVariable($variableValue)
	{
		if (is_string($variableValue) == true)
		{
			if (get_magic_quotes_gpc() == true)
			{
				$variableValue = stripslashes($variableValue);
			}
		}
		else if (is_array($variableValue) == true)
		{
			foreach ($variableValue as $key => $value)
			{
				$variableValue[$key] = $this->sanitizeVariable($value);
			}
		}
		
		
		return $variableValue;
	}
	
	
	/**
	 * Sets a variable and sanitizes it to prevent any attack
	 *
	 * @param 	string 	$variablePath 	The path to the variable
	 * @param 	string 	$variableName 	The name of the variable
	 * @param 	mixed 	$variableValue 	The value of the variable
	 * @param 	array 	$cookieOptions 	Options for the cookie only (can be null)
	 *
	 * @return	string 	The path to the variable
	 */
	
	public function setVariable($variablePath, $variableValue, $variableOptions = null)
	{
		// Extract the variable group/name
		
		$variableGroup = null;
		$variableName = null;
		
		$this->extractGroupAndNameFromPath($variablePath, $variableGroup, $variableName);
		
		
		// We can only set cookies, session and view variables
		
		if ($variableGroup == 'COOKIE')
		{
			$cookieDomain = pref('[Loop]/cookie/domain');

			if (empty($cookieDomain) === true)
			{
				$cookieDomain = v('SERVER::SERVER_NAME');
			}

			$cookieExpires = time() + pref('[Loop]/cookie/durationInMinutes') * 60;
			$cookiePath = '/';
			$cookieSecure = false;
			$cookieHttpOnly = false;
			
			if (isset($variableOptions['expires']) == true)
			{
				$cookieExpires = $variableOptions['expires'];
			}
			
			if (isset($variableOptions['path']) == true)
			{
				$cookiePath = $variableOptions['path'];
			}
			
			if (isset($variableOptions['domain']) == true)
			{
				$cookieDomain = $variableOptions['domain'];
			}
			
			if (isset($variableOptions['secure']) == true)
			{
				$cookieSecure = $variableOptions['secure'];
			}
			
			if (isset($variableOptions['httpOnly']) == true)
			{
				$cookieHttpOnly = $variableOptions['httpOnly'];
			}
			
			setcookie(pref('[Loop]/cookie/prefix') . $variableName, $variableValue, $cookieExpires, $cookiePath, $cookieDomain, $cookieSecure, $cookieHttpOnly);
		}
		else if ($variableGroup == 'SESSION')
		{
			$_SESSION[$variableName] = $variableValue;
		}
		else if
		(
			($variableGroup == 'GET') ||
			($variableGroup == 'POST') ||
			($variableGroup == 'SERVER')
		)
		{
			e
			(
				EXCEPTION_VARIABLE_CAN_NOT_BE_CHANGED,
				array('variablePath' => $variablePath)
			);
		}
		else
		{
			// Make sure the variable group is created
			
			if
			(
				(isset($this->variables[$variableGroup]) == false) ||
				(is_array($this->variables[$variableGroup]) == false)
			)
			{
				$this->variables[$variableGroup] = array();
			}
			
			
			// View variables are the only ones being sanitized
			
			$this->variables[$variableGroup][$variableName] = $variableValue;
			
			
			// Return the full path to the variable
			
			return $variableGroup . '::' . $variableName;
		}
	}
}

?>
